package com.tlgen.tomcat.utils;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.tlgen.tomcat.model.ErrorResult;
import com.tlgen.tomcat.model.RequestMethodAndUrl;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URLDecoder;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import static com.tlgen.tomcat.utils.StringRequestUtils.*;

public class CheckRequestUtils {

    /**
     * 校验请求路径 path 和请求类型
     *
     * @param socket
     * @param inputStream
     * @param requestLine
     * @return
     */
    public static RequestMethodAndUrl checkRequestPathAndRequestType(
            Socket socket, InputStream inputStream, String requestLine) {
        RequestMethodAndUrl currentRequestMethodAndUrl = null;
        try {
            // 获取请求方式
            String requestType = getRequestType(requestLine);
            // 获取请求 path
            String requestPath = getRequestPath(requestLine);

            // 判断请求路径是否正确
            boolean foundFlag = false;
            if (StrUtil.isNotBlank(requestPath)) {
                List<RequestMethodAndUrl> requestMethodAndUrls = Lists.newArrayList();
                AnnotationUtils.getRequestMappingClassesWithAnnotation().forEach(
                        item -> requestMethodAndUrls.addAll(item.getRequestMethodAndUrls()));
                // 获取对应该请求的方法
                String methodRequestPath = requestPath.indexOf("?") > 0
                        ? requestPath.substring(0, requestPath.indexOf("?")) : requestPath;
                currentRequestMethodAndUrl = requestMethodAndUrls.stream().filter(x -> {
                    if (Objects.equals(methodRequestPath, x.getUrl())) {
                        return true;
                    } else if (x.getUrl().indexOf("{") > 0) { // @PathVariable 接收参数的方式
                        String[] split1 = methodRequestPath.split("/");
                        String[] split2 = x.getUrl().split("/");
                        String prefixPath = x.getUrl().substring(0, x.getUrl().indexOf("{"));
                        return methodRequestPath.startsWith(prefixPath) && split1.length == split2.length;
                    }
                    return false;
                }).findFirst().orElse(null);
                if (Objects.nonNull(currentRequestMethodAndUrl)) {
                    foundFlag = true;
                    String url = currentRequestMethodAndUrl.getUrl();
                    // 获取 GET 请求参数名称和值
                    if (Objects.equals("GET", currentRequestMethodAndUrl.getRequestType())) {
                        if (requestPath.contains("?")) {
                            String parameterStr = requestPath.substring(requestPath.indexOf("?") + 1);
                            String[] split = parameterStr.split("&");
                            Object[] args = new Object[split.length];
                            for (int i = 0; i < split.length; i++) {
                                String[] kv = split[i].split("=");
                                args[i] = URLDecoder.decode(kv[1]);
                            }
                            currentRequestMethodAndUrl.setArgs(args);
                        } else if (url.indexOf("{") > 0) { // @PathVariable 接收参数的方式
                            getPathVariableParam(methodRequestPath, url, currentRequestMethodAndUrl);
                        }
                    }
                    // 获取 POST、PUT、DELETE JSON 请求参数名称和值
                    if (Lists.newArrayList("POST", "PUT", "DELETE").contains(currentRequestMethodAndUrl.getRequestType())) {
                        if (requestLine.indexOf("Content-Length") > 0
                                && requestLine.indexOf("[") > 0
                                && requestLine.indexOf("[") < requestLine.indexOf("{")) { // 是数组上送
                            String substring = requestLine.substring(requestLine.indexOf("Content-Length"));
                            String requestBody = substring.substring(substring.indexOf("["));
                            Object[] args = new Object[1];
                            args[0] = requestBody;
                            currentRequestMethodAndUrl.setArgs(args);
                        } else if ((requestLine.indexOf("Content-Length") > 0
                                && requestLine.indexOf("[") > 0
                                && requestLine.indexOf("{") > 0
                                && requestLine.indexOf("[") > requestLine.indexOf("{"))
                                || (requestLine.indexOf("Content-Length") > 0 && requestLine.indexOf("{") > 0)) { // 是对象上送
                            String substring = requestLine.substring(requestLine.indexOf("Content-Length"));
                            String requestBody = substring.substring(substring.indexOf("{"));
                            Object[] args = new Object[1];
                            args[0] = requestBody;
                            currentRequestMethodAndUrl.setArgs(args);
                        } else if (requestLine.indexOf("Content-Disposition: form-data;") > 0) {
                            // 获取 POST、PUT、DELETE 请求中的 form-data 请求参数
                            List<String> requestFormDataParam = getRequestFormDataParam(requestLine);
                            Object[] args = new Object[requestFormDataParam.size()];
                            for (int i = 0; i < requestFormDataParam.size(); i++) {
                                args[i] = requestFormDataParam.get(i);
                            }
                            currentRequestMethodAndUrl.setArgs(args);
                        } else if (url.indexOf("{") > 0) { // 获取 POST、PUT、DELETE 请求参数名称和值, @PathVariable 接收参数的方式
                            getPathVariableParam(methodRequestPath, url, currentRequestMethodAndUrl);
                        }
                    }
                }
            }
            if (!foundFlag) {
                // 返回 404
                OutputStream outputStream = socket.getOutputStream();
                String respHeader = "HTTP/1.1 404\r\n" +
                        "Content-Type: text/html;charset=utf-8\r\n\r\n";
                String response = respHeader + " " + JSONObject.toJSONString(
                        ErrorResult.builder()
                                .timestamp(String.valueOf(new Date().getTime()))
                                .status(404)
                                .error("404 Not Found")
                                .path(requestPath)
                                .build());
                outputStream.write(response.getBytes());
                outputStream.flush();
                outputStream.close();
                inputStream.close();
            }

            // 校验请求方式
            if (Objects.nonNull(currentRequestMethodAndUrl)) {
                if (!Objects.equals(currentRequestMethodAndUrl.getRequestType(), requestType)) {
                    // 返回 405
                    OutputStream outputStream = socket.getOutputStream();
                    String respHeader = "HTTP/1.1 405\r\n" +
                            "Content-Type: text/html;charset=utf-8\r\n\r\n";
                    String response = respHeader + " " + JSONObject.toJSONString(
                            ErrorResult.builder()
                                    .timestamp(String.valueOf(new Date().getTime()))
                                    .status(405)
                                    .error("Method Not Allowed")
                                    .path(requestPath)
                                    .build());
                    outputStream.write(response.getBytes());
                    outputStream.flush();
                    outputStream.close();
                    inputStream.close();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return currentRequestMethodAndUrl;
    }

}
